<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <script src="https://unpkg.com/react@18.1.0/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom@18.1.0/umd/react-dom.development.js"></script>
    <script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>
    <title>Document</title>
  </head>
  <body>
    <div id="app"></div>
    <script type="text/babel">
      /*
      shouldComponentUpdate() 是在对新旧数据进行比较，发现数据改变，从而触发render，组件渲染更新。
      但是对于基本数据类型string/boolean/number，shouldComponentUpdate可以很好的识别；对于引用数据类型array/object，shouldComponentUpdate识别不了对象内部属性或元素的变化，因为引用类型指向的都是指向的同一个对象的内存地址。
      解决shouldComponentUpdate正确识别对象/数组内部属性变化的唯一方式就是：基于旧对象生成新对象。
      基于旧对象生成新对象的方式：
      1. {...}展开运算符；和 JSON 对象两个方法；弊端是对于内容复杂的对象来说，每次都将所有节点复制生成新节点，比较浪费内存和CPU性能；
      2. 使用Immutable不可变对象生成新对象；一方面它会基于旧对象生成新对象；同时会对没有发生变化的节点数据进行内存共享，减少重复性的节点复制操作，减少内存浪费和CPU计算的消耗；
        - Immutable不可变对象，表示原始对象不可修改变化，一旦你对原始不可变对象产生了修改了行为，它会返回一个新的经过深拷贝之后的对象。
      */
      class App extends React.Component {
        constructor() {
          super();
          this.state = {
            user: Immutable({
              // Immutable(array|object) 等同于 Immutable.from(array|object)，获取不可变对象。
              uname: "小明",
              other: {
                address: "郑州市",
              },
            }),
            list: Immutable([10, 20, 30]),
          };
        }
        shouldComponentUpdate(nextProps, nextState) {
          console.log(nextState.user === this.state.user);
          if (
            nextState.user === this.state.user &&
            nextState.list === this.state.list
          ) {
            console.log("同一个对象, 不需要render");
            return false;
          }
          console.log("不是同一个对象, 需要render");
          return true;
        }
        render() {
          console.log("app render 了");
          return (
            <div className="app">
              <h3>App组件</h3>
              <p>{JSON.stringify(this.state.user)}</p>
              <button
                onClick={() => {
                  let { user } = this.state;
                  // console.log(user);

                  // Immutable.setIn(不可变对象, [第一层属性, 第二层属性...], 新值)：对象必须通过它修改属性值。
                  let newUser = Immutable.setIn(user, ["uname"], "小明");
                  newUser = Immutable.setIn(
                    newUser,
                    ["other", "address"],
                    "郑州市"
                  );
                  this.setState({ user: Immutable(newUser) });
                }}
              >
                设置user
              </button>
              <p>{this.state.list.join("-")}</p>
              <button
                onClick={() => {
                  // Immutable.asMutable(不可变数组) 该方法返回不可变数据的可变副本。
                  let newList = Immutable.asMutable(this.state.list);
                  // newList = Immutable.setIn(newList, ["0"], 100);
                  newList[0] = 1000; // 数组中是基本数据类型，可以直接修改，也可以向上面一样，调用setIn修改数据元素。数组中是对象{}，必须调用setIn修改属性。
                  this.setState({ list: newList });
                }}
              >
                设置list
              </button>
            </div>
          );
        }
      }
      ReactDOM.render(<App />, document.getElementById("app"));
    </script>
  </body>
</html>
